﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Hybrid;
using System.Diagnostics;

namespace Hybrid
{
    public partial class Main : Form
    {
        Graphics g;
        Bitmap b;
        Bitmaps BitmapCollection = new Bitmaps();
        Timer GameUpdate = new Timer();
        Timer EnemyUpdate = new Timer();
        Timer GarbageTimer = new Timer();
        Timer StatsTimer = new Timer();
        Timer GameOverTimer = new Timer();
        Timer EnemyProjTimer = new Timer();
        Timer PowerUpTimer = new Timer();
        int MaxWidth = 730;
        int MaxHeight = 570;
        Random GlobalRandom = new Random();
        List<PlayerShip> PlayerShips = new List<PlayerShip>();
        List<Enemy> EnemyShips = new List<Enemy>();
        List<PowerUp> PowerUps = new List<PowerUp>();
        Background BackgroundClass = new Background();
        SoundEffects SoundEffect = new SoundEffects();
        PowerUpTypes PowerUpType = new PowerUpTypes();
        Leveling Levels;
        bool GameOver = false;
        bool GamePaused = false;
        bool NetworkGame = false;
        bool GameHost = false;

        public Main(int PlayerAmount, int LevelIndex, int[] scores, bool NetworkGame, bool gamehost)
        {
            this.NetworkGame = NetworkGame;
            this.GameHost = gamehost;

            InitializeComponent();
            List<Label> TitleLabels = new List<Label>() { title0, title1, title2 };
            List<Label> ScoreLabels = new List<Label>() { points0, points1, points2 };
            List<ProgressBar> healthBars = new List<ProgressBar>() { health0, health1, health2 };
            SoundEffect.Ambience();

            for (int i = 0; i <= PlayerAmount; i++)
            {
                PlayerShips.Add(new PlayerShip(BitmapCollection.ShipBitmap(i), new KeySet(PlayerAmount, i), PlayerAmount, i, i, BitmapCollection.ProjectileBitmap(0), TitleLabels[i], healthBars[i], ScoreLabels[i]));
                if (scores != null) PlayerShips[i].Score = scores[i];
            }
            
            this.DoubleBuffered = true;
            b = new Bitmap(BackgroundClass.Image, MaxWidth, MaxHeight);
            g = Graphics.FromImage(b);
            this.GameUpdate.Interval = 50;
            this.GameUpdate.Tick += new EventHandler(GameUpdate_Tick);
            this.GameUpdate.Start();
            this.KeyDown += new KeyEventHandler(Main_KeyDown);
            this.KeyUp += new KeyEventHandler(Main_KeyUp);
            this.FormClosing += new FormClosingEventHandler(Main_FormClosing);
            EnemyUpdate.Interval = 2200;
            EnemyUpdate.Tick += new EventHandler(EnemyUpdate_Tick);
            EnemyUpdate.Start();
            GarbageTimer.Interval = 600;
            GarbageTimer.Tick += new EventHandler(GarbageTimer_Tick);
            GarbageTimer.Start();
            StatsTimer.Interval = 500;
            StatsTimer.Tick += new EventHandler(StatsTimer_Tick);
            StatsTimer.Start();
            GameOverTimer.Interval = 250;
            GameOverTimer.Tick += new EventHandler(GameOverTimer_Tick);
            EnemyProjTimer.Interval = 1250;
            EnemyProjTimer.Tick += new EventHandler(EnemyProjTimer_Tick);
            EnemyProjTimer.Start();
            PowerUpTimer.Interval = 10000;
            PowerUpTimer.Tick += new EventHandler(PowerUpTimer_Tick);
            PowerUpTimer.Start();

            Levels = new Leveling(LevelIndex, BackgroundClass, GameUpdate, EnemyUpdate, g, EnemyShips, BitmapCollection, EnemyProjTimer, SoundEffect, PlayerShips, pictureBox1, b);
            BackgroundClass.SetLevel(Levels);
        }

        void Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            Application.Exit();
        }

        void PowerUpTimer_Tick(object sender, EventArgs e)
        {
            if (!Levels.WaitScreen)
            {
                int ranIndex = GlobalRandom.Next(0, 4);
                PowerUps.Add(PowerUpType.NewRandomPowerUp(ranIndex, GlobalRandom.Next(0, 730 - BitmapCollection.PowerUpBitmap(ranIndex)[0].Width), BitmapCollection.PowerUpBitmap(ranIndex)));
            }
        }

        void EnemyProjTimer_Tick(object sender, EventArgs e)
        {
            if (!Levels.WaitScreen)
            {
                EnemyProjTimer.Interval = Levels.EnemyFireProj;
                EnemyFireProj();
            }
        }

        void EnemyFireProj()
        {
            if (!Levels.WaitScreen)
            {
                if (EnemyShips.Count > 0)
                {
                    Enemy firEnemy = EnemyShips[GlobalRandom.Next(0, EnemyShips.Count)];
                    if (firEnemy.Object.Y < MaxHeight / 2)
                    {
                        firEnemy.FireProjectile();
                        SoundEffect.EnemyFire();
                        EnemyProjTimer.Interval = GlobalRandom.Next(Levels.EnemyFireProj, Levels.EnemyFireProj * 2);
                    }
                }
            }
        }

        void StatsTimer_Tick(object sender, EventArgs e)
        {
            label1.Text = "Memory Usage: " + String.Format("{0:0,0}", (Process.GetCurrentProcess().PrivateMemorySize64 / 1024)) + " KB";
            label2.Text = "Enemy Count: " + EnemyShips.Count.ToString();

            int proj = 0;
            for (int i = 0; i < PlayerShips.Count; i++)
            {
                proj += PlayerShips[i].Projectiles.Count;
            }
            label3.Text = "Projectile Count: " + proj;
            label5.Text = "PowerUp Count: " + PowerUps.Count;
        }

        void GarbageTimer_Tick(object sender, EventArgs e)
        {
            for (int i = 0; i < EnemyShips.Count; i++)
            {
                if (!EnemyShips[i].Object.InBounds(3))
                {
                    EnemyShips.RemoveAt(i);
                    i--;
                    SoundEffect.EnemyExplosion();
                    progressBar1.Value -= 50;
                    if (progressBar1.Value == 0) GameOverTimer.Start();
                }
            }

            for (int i = 0; i < PlayerShips.Count; i++)
            {
                for (int f = 0; f < PlayerShips[i].Projectiles.Count; f++)
                {
                    if (!PlayerShips[i].Projectiles[f].Object.InBounds(2))
                    {
                        PlayerShips[i].Projectiles.RemoveAt(f);
                        f--;
                    }
                }
            }

            for (int i = 0; i < PowerUps.Count; i++)
            {
                if (!PowerUps[i].Object.InBounds(3))
                {
                    PowerUps.RemoveAt(i);
                    i--;
                }
            }
        }

        public Control GetControl(string type, int index)
        {
            MessageBox.Show(type);
            return this.Controls.Find("type", false)[0];
        }

        void EnemyUpdate_Tick(object sender, EventArgs e)
        {
            if (!Levels.WaitScreen)
            {
                EnemyUpdate.Interval = Levels.EnemyInterval;
                EnemyShips.Add(new Enemy(BitmapCollection.EnemyBitmap(GlobalRandom.Next(0, BitmapCollection.EnemyCount)), BitmapCollection.ProjectileBitmap(1), GlobalRandom.Next(Levels.EnemySpeed, Levels.EnemySpeed + 2)));
            }
        }

        void GameUpdate_Tick(object sender, EventArgs e)
        {
            if (!Levels.WaitScreen)
            {
                g.Clear(Color.Black);

                BackgroundClass.DrawBackground(g);

                try
                {
                    for (int i = 0; i < PlayerShips.Count; i++)
                    {
                        for (int t = 0; t < EnemyShips.Count; t++)
                        {
                            if (!PlayerShips[i].Object(true).DestroyStarted && !EnemyShips[t].Object.DestroyStarted && PlayerShips[i].Object(true).CollisionDetected(EnemyShips[t].Object))
                            {
                                EnemyShips[t].Object.StartDestroy();
                                SoundEffect.EnemyExplosion();
                                PlayerShips[i].DamageShip(20);
                                bool gameOver = true;
                                for (int j = 0; j < PlayerShips.Count; j++)
                                {
                                    if (PlayerShips[j].Object(true).DestroyStarted == false) gameOver = false;
                                }
                                if (gameOver) GameOverTimer.Start();
                                break;
                            }
                        }
                    }
                }
                catch { }

                try
                {
                    for (int i = 0; i < PlayerShips.Count; i++)
                    {
                        for (int f = 0; f < PlayerShips[i].Projectiles.Count; f++)
                        {
                            DrawObject(PlayerShips[i].Projectiles[f].Object);
                            for (int t = 0; t < EnemyShips.Count; t++)
                            {
                                if (EnemyShips[t].Object.CollisionDetected(PlayerShips[i].Projectiles[f].Object))
                                {
                                    PlayerShips[i].Projectiles.RemoveAt(f);
                                    EnemyShips[t].Object.StartDestroy();
                                    SoundEffect.EnemyExplosion();
                                    PlayerShips[i].Score += 10;
                                    break;
                                }
                            }
                        }
                        DrawObject(PlayerShips[i].Object(false));
                    }
                }
                catch { }

                try
                {
                    for (int i = 0; i < EnemyShips.Count; i++)
                    {
                        DrawObject(EnemyShips[i].Object);
                        for (int f = 0; f < EnemyShips[i].Projectiles.Count; f++)
                        {
                            DrawObject(EnemyShips[i].Projectiles[f].Object);
                            for (int t = 0; t < PlayerShips.Count; t++)
                            {
                                if (PlayerShips[t].Object(true).CollisionDetected(EnemyShips[i].Projectiles[f].Object))
                                {
                                    SoundEffect.PlayerShipLaserHit();
                                    EnemyShips[i].Projectiles.RemoveAt(f);
                                    PlayerShips[t].DamageShip(10);
                                    bool gameOver = true;
                                    for (int j = 0; j < PlayerShips.Count; j++)
                                    {
                                        if (PlayerShips[j].Object(true).DestroyStarted == false) gameOver = false;
                                    }
                                    if (gameOver) GameOverTimer.Start();
                                }

                            }
                        }
                        if (EnemyShips[i].Object.Destroyed)
                        {
                            EnemyShips.RemoveAt(i);
                            i--;
                        }
                    }
                }
                catch { }

                try
                {
                    for (int i = 0; i < PowerUps.Count; i++)
                    {
                        for (int f = 0; f < PlayerShips.Count; f++)
                        {
                            DrawObject(PowerUps[i].Object);
                            if (PlayerShips[f].Object(true).CollisionDetected(PowerUps[i].Object))
                            {
                                PlayerShips[f].ApplyPowerUp(PowerUps[i].Values);
                                PowerUps.RemoveAt(i);
                                i--;
                            }
                        }

                    }
                }
                catch { }

                pictureBox1.Image = b;
            }
        }

        void GameOverTimer_Tick(object sender, EventArgs e)
        {
            GameUpdate.Stop();
            EnemyUpdate.Stop();
            EnemyProjTimer.Stop();
            GarbageTimer.Stop();
            g.DrawString("GAME OVER", new Font("Arial", 30, FontStyle.Bold), Brushes.Red, new PointF(240, 200));
            g.DrawString("PRESS N FOR NEW GAME", new Font("Arial", 18, FontStyle.Bold), Brushes.DarkSlateBlue, new PointF(220, 290));
            pictureBox1.Image = b;
            GameOver = true;
        }

        void DrawObject(Sprite SpriteObject)
        {
            g.DrawImage(SpriteObject.Image, SpriteObject.NewX, SpriteObject.NewY, SpriteObject.Width, SpriteObject.Height);
        }

        #region Keys
        void Main_KeyDown(object sender, KeyEventArgs e)
        {
            if (!GamePaused)
            {
                SendKeys(e.KeyCode, true);
            }
            if (GameOver)
            {
                if (e.KeyCode == Keys.N)
                {
                    Application.Restart();
                }
            }
            else
            {
                if (e.KeyCode == Keys.F1)
                {
                    if (GamePaused)
                    {
                        GameUpdate.Start();
                        EnemyUpdate.Start();
                        GarbageTimer.Start();
                        EnemyProjTimer.Start();
                        GamePaused = false;
                    }
                    else
                    {
                        GameUpdate.Stop();
                        EnemyUpdate.Stop();
                        GarbageTimer.Stop();
                        EnemyProjTimer.Stop();
                        GamePaused = true;
                    }
                }
            }

        }

        public void SendKeys(Keys KeyChar, bool keyDown)
        {
            foreach (PlayerShip PS in PlayerShips)
            {
                PS.KeyRunThrough(KeyChar, keyDown);
            }
        }

        void Main_KeyUp(object sender, KeyEventArgs e)
        {
            SendKeys(e.KeyCode, false);
        }
        #endregion
    }
}
